package org.geometerplus.zlibrary.ui.android.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import com.shwread.android.qysw.activity.ReadingBookActivity;
import com.shwread.android.qysw10000152.R;
import org.geometerplus.fbreader.fbreader.ActionCode;
import org.geometerplus.zlibrary.core.application.ZLApplication;
import org.geometerplus.zlibrary.core.view.ZLView;
import org.geometerplus.zlibrary.core.view.ZLViewWidget;
import org.geometerplus.zlibrary.text.view.ZLTextElementArea;
import org.geometerplus.zlibrary.text.view.ZLTextView;

import logic.util.logutil.LogUtil;


/**
 * 书本渲染页面
 * 
 * @author Administrator
 */
public class LQReadingView
        extends
        View
        implements
        ZLViewWidget,
        View.OnLongClickListener
{
	
	private final Paint         myPaint         = new Paint();
	private final BitmapManager myBitmapManager = new BitmapManager(this);
	private Bitmap              myFooterBitmap;
	private Bitmap              myHeaderBitmap;
	private ZLAndroidPaintContext myInitPaintContext = null;
	
	public LQReadingView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	
	public LQReadingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	public LQReadingView(Context context) {
		super(context);
		init();
	}
	
	private void init() {
		// next line prevent ignoring first onKeyDown DPad event
		// after any dialog was closed
		setFocusableInTouchMode(true);
		setDrawingCacheEnabled(false);
		setOnLongClickListener(this);
	}
	
	public ZLAndroidPaintContext getInitPaintContext( ) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		int scrollBarWidth = 0;
		if (view != null && view.isScrollbarShown()) { 
			scrollBarWidth = getVerticalScrollbarWidth() ;
		}
		
		if(myInitPaintContext == null ) {
			myInitPaintContext = new ZLAndroidPaintContext(new Canvas( ), getWidth(), getMainAreaHeight(), scrollBarWidth);
			return myInitPaintContext;
		}
		
		int width = getWidth() - scrollBarWidth;
		myInitPaintContext.setMyWidth(width);
		myInitPaintContext.setMyHeight(getMainAreaHeight());
		return myInitPaintContext;
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		getAnimationProvider().terminate();
		if (myScreenIsTouched)
		{
			final ZLView view = ZLApplication.Instance().getCurrentView();
			myScreenIsTouched = false;
			view.onScrollingFinished(ZLView.PageIndex.current);
		}
	}
	
	@Override
	protected void onDraw(final Canvas canvas) {
		LogUtil.d("luhuhai", "onDraw");
		final Context context = getContext();
		if (context instanceof ReadingBookActivity)
		{
			((ReadingBookActivity) context).createWakeLock();
		}
		else
		{
			System.err.println("A surprise: view's context is not an FBReader");
		}
		super.onDraw(canvas);
		
		//		final int w = getWidth();
		//		final int h = getMainAreaHeight();
		
		if (getAnimationProvider().inProgress())
		{
			onDrawInScrolling(canvas);
		}
		else
		{
			onDrawStatic(canvas);
			ZLApplication.Instance().onRepaintFinished();
		}
	}
	
	private AnimationProvider myAnimationProvider;
	private ZLView.Animation  myAnimationType;
	
	private AnimationProvider getAnimationProvider() {
		final ZLView.Animation type = ZLApplication.Instance().getCurrentView().getAnimationType();
		if (myAnimationProvider == null || myAnimationType != type)
		{
			myAnimationType = type;
			switch (type) {
				case none:
					myAnimationProvider = new NoneAnimationProvider(myBitmapManager);
					break;
				case curl:
					myAnimationProvider = new CurlAnimationProvider(myBitmapManager);
					break;
				case slide:
					myAnimationProvider = new SlideAnimationProvider(myBitmapManager);
					break;
				case shift:
					myAnimationProvider = new ShiftAnimationProvider(myBitmapManager);
					break;
			}
		}
		return myAnimationProvider;
	}
	
	private void onDrawInScrolling(Canvas canvas) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		
		//		final int w = getWidth();
		//		final int h = getMainAreaHeight();
		
		final AnimationProvider animator = getAnimationProvider();
		final AnimationProvider.Mode oldMode = animator.getMode();
		animator.doStep();
		if (animator.inProgress())
		{
			animator.draw(canvas);
			if (animator.getMode().Auto)
			{
				postInvalidate();
			}
			drawFooter(canvas);
			drawHeader(canvas);
		}
		else
		{
			switch (oldMode) {
				case AnimatedScrollingForward: {
					final ZLView.PageIndex index = animator.getPageToScrollTo();
					myBitmapManager.shift(index == ZLView.PageIndex.next);
					view.onScrollingFinished(index);
					ZLApplication.Instance().onRepaintFinished();
					break;
				}
				case AnimatedScrollingBackward:
					view.onScrollingFinished(ZLView.PageIndex.current);
					break;
			}
			onDrawStatic(canvas);
		}
	}
	
	@Override
	public void reset() {
		myBitmapManager.reset();
	}
	
	@Override
	public void repaint() {
		postInvalidate();
	}
	
	@Override
	public void startManualScrolling(int x, int y, ZLView.Direction direction) {
		final AnimationProvider animator = getAnimationProvider();
		animator.setup(direction, getWidth(), getMainAreaHeight());
		animator.startManualScrolling(x, y);
	}
	
	@Override
	public void scrollManuallyTo(int x, int y) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		final AnimationProvider animator = getAnimationProvider();
		if (view.canScroll(animator.getPageToScrollTo(x, y)))
		{
			animator.scrollTo(x, y);
			postInvalidate();
		}
	}
	
	@Override
	public void startAnimatedScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex))
		{
			if (System.currentTimeMillis() - tempTime < 5000) return;
			//#debug
			base.tina.core.log.LogPrinter.e("trun page", "startAnimatedScrolling  : " + pageIndex);
			ZLApplication.Instance().runAction(ActionCode.OPEN_ONLINE_BOOKS, pageIndex);
			tempTime = System.currentTimeMillis();
			return;
		}
		final AnimationProvider animator = getAnimationProvider();
		animator.setup(direction, getWidth(), getMainAreaHeight());
		animator.startAnimatedScrolling(pageIndex, x, y, speed);
		if (animator.getMode().Auto)
		{
			postInvalidate();
		}
	}
	
	@Override
	public void startAnimatedScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed) {
		
		final ZLView view = ZLApplication.Instance().getCurrentView();
		if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex))
		{
			if (System.currentTimeMillis() - tempTime < 5000) return;
			//#debug
			base.tina.core.log.LogPrinter.e("turn page", "!!!!!!!startAnimatedScrolling");
			ZLApplication.Instance().runAction(ActionCode.OPEN_ONLINE_BOOKS, pageIndex);
			tempTime = System.currentTimeMillis();
			return;
		}
		final AnimationProvider animator = getAnimationProvider();
		animator.setup(direction, getWidth(), getMainAreaHeight());
		animator.startAnimatedScrolling(pageIndex, null, null, speed);
		if (animator.getMode().Auto)
		{
			postInvalidate();
		}
	}
	
	long             tempTime     = 0;
	ZLView.PageIndex tempAnimated = ZLView.PageIndex.current;
	
	@Override
	public void startAnimatedScrolling(int x, int y, int speed) {
		
		final ZLView view = ZLApplication.Instance().getCurrentView();
		final AnimationProvider animator = getAnimationProvider();
		if (!view.canScroll(animator.getPageToScrollTo(x, y)))
		{
			
			if (System.currentTimeMillis() - tempTime < 5000 && tempAnimated == animator.getPageToScrollTo(x, y)) return;
			//#debug
			base.tina.core.log.LogPrinter.e("turn page", "startAnimatedScrolling2:" + animator.getPageToScrollTo(x, y));
			ZLApplication.Instance().runAction(ActionCode.OPEN_ONLINE_BOOKS, animator.getPageToScrollTo(x, y));
			tempTime = System.currentTimeMillis();
			tempAnimated = animator.getPageToScrollTo(x, y);
			animator.terminate();
			return;
		}
		animator.startAnimatedScrolling(x, y, speed);
		postInvalidate();
	}
	
	void drawOnBitmap(Bitmap bitmap, ZLView.PageIndex index) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		if (view == null) { return; }
		
		final ZLAndroidPaintContext context = new ZLAndroidPaintContext(new Canvas(bitmap), getWidth(), getMainAreaHeight(), view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);
		view.paint(context, index);
		
		//画上笔记的icon
		
		drawRemarkIcons(context, view, index);
	}
	
	private void drawRemarkIcons(ZLAndroidPaintContext context, ZLView view, ZLView.PageIndex index) {
		//画上笔记的icon
		for (ZLTextElementArea area : ((ZLTextView) view).getRemarkIconZLTextElementAreas(index))
		{
			if (area != null)
			{
				Bitmap remarkIcon = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.note_tag);
				ICON_HEIGHT = remarkIcon.getHeight();
				ICON_WIDTH = remarkIcon.getWidth();
				context.drawRemarkIcon(remarkIcon, area.XEnd, area.YEnd);
			}
		}
	}
	
	public static int ICON_HEIGHT;
	public static int ICON_WIDTH;
	
	private void drawHeader(Canvas canvas) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		final ZLView.HeaderArea header = view.getHeaderArea();
		
		if (header == null)
		{
			myHeaderBitmap = null;
			return;
		}
		
		if (myHeaderBitmap != null && (myHeaderBitmap.getWidth() != getWidth() || myHeaderBitmap.getHeight() != header.getHeight()))
		{
			myHeaderBitmap = null;
		}
		if (myHeaderBitmap == null)
		{
			myHeaderBitmap = Bitmap.createBitmap(getWidth(), header.getHeight(), Bitmap.Config.RGB_565);
		}
		final ZLAndroidPaintContext context = new ZLAndroidPaintContext(new Canvas(myHeaderBitmap), getWidth(), header.getHeight(), view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);
		header.paint(context);
		canvas.drawBitmap(myHeaderBitmap, 0, 0, myPaint);
	}
	
	private void drawFooter(Canvas canvas) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		final ZLView.FooterArea footer = view.getFooterArea();
		
		if (footer == null)
		{
			myFooterBitmap = null;
			return;
		}
		
		if (myFooterBitmap != null && (myFooterBitmap.getWidth() != getWidth() || myFooterBitmap.getHeight() != footer.getHeight()))
		{
			myFooterBitmap = null;
		}
		if (myFooterBitmap == null)
		{
			myFooterBitmap = Bitmap.createBitmap(getWidth(), footer.getHeight(), Bitmap.Config.RGB_565);
		}
		final ZLAndroidPaintContext context = new ZLAndroidPaintContext(new Canvas(myFooterBitmap), getWidth(), footer.getHeight(), view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);
		footer.paint(context);
		canvas.drawBitmap(myFooterBitmap, 0, getHeight() - footer.getHeight(), myPaint);
	}
	
	private void onDrawStatic(final Canvas canvas) {
		myBitmapManager.setSize(getWidth(), getMainAreaHeight());
		Bitmap bmp = myBitmapManager.getBitmap(ZLView.PageIndex.current);
		canvas.drawBitmap(bmp, 0, getHeaderAreaHeight(), myPaint);
		drawFooter(canvas);
		drawHeader(canvas);
	}
	
	@Override
	public boolean onTrackballEvent(MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_DOWN)
		{
			onKeyDown(KeyEvent.KEYCODE_DPAD_CENTER, null);
		}
		else
		{
			ZLApplication.Instance().getCurrentView().onTrackballRotated((int) (10 * event.getX()), (int) (10 * event.getY()));
		}
		return true;
	}
	
	private class LongClickRunnable
	        implements
	        Runnable
	{
		@Override
		public void run() {
			if (performLongClick())
			{
				myLongClickPerformed = true;
			}
		}
	}
	
	private volatile LongClickRunnable myPendingLongClickRunnable;
	private volatile boolean           myLongClickPerformed;
	
	private void postLongClickRunnable() {
		myLongClickPerformed = false;
		myPendingPress = false;
		if (myPendingLongClickRunnable == null)
		{
			myPendingLongClickRunnable = new LongClickRunnable();
		}
		postDelayed(myPendingLongClickRunnable, 2 * ViewConfiguration.getLongPressTimeout());
	}
	
	private class ShortClickRunnable
	        implements
	        Runnable
	{
		@Override
		public void run() {
			final ZLView view = ZLApplication.Instance().getCurrentView();
			view.onFingerSingleTap(myPressedX, myPressedY);
			myPendingPress = false;
			myPendingShortClickRunnable = null;
		}
	}
	
	private volatile ShortClickRunnable myPendingShortClickRunnable;
	
	private volatile boolean            myPendingPress;
	private volatile boolean            myPendingDoubleTap;
	private int                         myPressedX, myPressedY;
	private boolean                     myScreenIsTouched;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int x = (int) event.getX();
		int y = (int) event.getY();
		
		final ZLView view = ZLApplication.Instance().getCurrentView();
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				if (myPendingShortClickRunnable != null)
				{
					removeCallbacks(myPendingShortClickRunnable);
					myPendingShortClickRunnable = null;
					myPendingDoubleTap = true;
				}
				else
				{
					postLongClickRunnable();
					myPendingPress = true;
				}
				myScreenIsTouched = true;
				myPressedX = x;
				myPressedY = y;
				break;
			case MotionEvent.ACTION_UP:
				if (myPendingDoubleTap)
				{
					view.onFingerDoubleTap(x, y);
				}
				else if (myLongClickPerformed)
				{
					view.onFingerReleaseAfterLongPress(x, y);
				}
				else
				{
					if (myPendingLongClickRunnable != null)
					{
						removeCallbacks(myPendingLongClickRunnable);
						myPendingLongClickRunnable = null;
					}
					if (myPendingPress)
					{
						if (view.isDoubleTapSupported())
						{
							if (myPendingShortClickRunnable == null)
							{
								myPendingShortClickRunnable = new ShortClickRunnable();
							}
							postDelayed(myPendingShortClickRunnable, ViewConfiguration.getDoubleTapTimeout());
						}
						else
						{
							view.onFingerSingleTap(x, y);
						}
					}
					else
					{
						view.onFingerRelease(x, y);
					}
				}
				myPendingDoubleTap = false;
				myPendingPress = false;
				myScreenIsTouched = false;
				break;
			case MotionEvent.ACTION_MOVE: {
				final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
				final boolean isAMove = Math.abs(myPressedX - x) > slop || Math.abs(myPressedY - y) > slop;
				if (isAMove)
				{
					myPendingDoubleTap = false;
				}
				if (myLongClickPerformed)
				{
					view.onFingerMoveAfterLongPress(x, y);
				}
				else
				{
					if (myPendingPress)
					{
						if (isAMove)
						{
							if (myPendingShortClickRunnable != null)
							{
								removeCallbacks(myPendingShortClickRunnable);
								myPendingShortClickRunnable = null;
							}
							if (myPendingLongClickRunnable != null)
							{
								removeCallbacks(myPendingLongClickRunnable);
							}
							view.onFingerPress(myPressedX, myPressedY);
							myPendingPress = false;
						}
					}
					if (!myPendingPress)
					{
						view.onFingerMove(x, y);
					}
				}
				break;
			}
		}
		
		return true;
	}
	
	@Override
	public boolean onLongClick(View v) {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		return view.onFingerLongPress(myPressedX, myPressedY);
	}
	
	@Override
	protected int computeVerticalScrollExtent() {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		if (!view.isScrollbarShown()) { return 0; }
		final AnimationProvider animator = getAnimationProvider();
		if (animator.inProgress())
		{
			final int from = view.getScrollbarThumbLength(ZLView.PageIndex.current);
			final int to = view.getScrollbarThumbLength(animator.getPageToScrollTo());
			final int percent = animator.getScrolledPercent();
			return (from * (100 - percent) + to * percent) / 100;
		}
		else
		{
			return view.getScrollbarThumbLength(ZLView.PageIndex.current);
		}
	}
	
	@Override
	protected int computeVerticalScrollOffset() {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		if (!view.isScrollbarShown()) { return 0; }
		final AnimationProvider animator = getAnimationProvider();
		if (animator.inProgress())
		{
			final int from = view.getScrollbarThumbPosition(ZLView.PageIndex.current);
			final int to = view.getScrollbarThumbPosition(animator.getPageToScrollTo());
			final int percent = animator.getScrolledPercent();
			return (from * (100 - percent) + to * percent) / 100;
		}
		else
		{
			return view.getScrollbarThumbPosition(ZLView.PageIndex.current);
		}
	}
	
	@Override
	protected int computeVerticalScrollRange() {
		final ZLView view = ZLApplication.Instance().getCurrentView();
		if (!view.isScrollbarShown()) { return 0; }
		return view.getScrollbarFullSize();
	}
	
	private int getMainAreaHeight() {
		final ZLView.FooterArea footer = ZLApplication.Instance().getCurrentView().getFooterArea();
		return footer != null ? getHeight() - getHeaderAreaHeight() - footer.getHeight() : getHeight();
	}
	
	private int getHeaderAreaHeight() {
		final ZLView.HeaderArea header = ZLApplication.Instance().getCurrentView().getHeaderArea();
		return header != null ? header.getHeight() : 0;
	}
}
